#include "DecoderClientThread.h"

#ifdef USE_DECODERS
AVInputFormat mp3_demuxer = {
    "mp3",
    NULL_IF_CONFIG_SMALL("MPEG audio layer 2/3"),
    0,
    mp3_read_probe,
    mp3_read_header,
    mp3_read_packet,
    .flags= AVFMT_GENERIC_INDEX,
    .extensions = "mp2,mp3,m2a", /* XXX: use probe */
    .metadata_conv = ff_id3v2_metadata_conv,
};
#endif

DecoderClient::DecoderClient(MediaSink* ptrSink)
{
	tas.decoder = this;
	sink = (MRSink*) ptrSink;
}


DecoderClient::~DecoderClient()
{
	//Nothing
}


int DecoderClient::configureThread()
{
	//Create and initialize a control variable
	int returnVal = 0;

	//Initialize thread attributes
	if((returnVal = pthread_attr_init(&threadAttr))!=0)
	{
		cout << "ERROR : Cannot initialize thread attributes for the thread creation with error "<< returnVal << " - " << strerror(returnVal) << endl;
		return returnVal;
	}

	//Get the scheduler parameters
	if((returnVal = pthread_attr_getschedparam(&threadAttr, &threadSchedParam))!=0)
	{
		cout << "ERROR : Cannot get the scheduler parameter for thread creation with error "<< returnVal << " - " << strerror(returnVal) << endl;
		return returnVal;
	}

	//Assign FIFO policy to the scheduler
	if((returnVal = pthread_attr_setschedpolicy(&threadAttr, SCHED_FIFO))!=0)
	{
		cout << "ERROR : Cannot set the scheduler policy to SCHED_FIFO for the thread creation with error "<< returnVal << " - " << strerror(returnVal) << endl;
		return returnVal;
	}

	//Set the thread priority as high as possible (i.e. 90)
	threadSchedParam.sched_priority = 90;

	//Assign the parameters to the thread
	if((returnVal = pthread_attr_setschedparam(&threadAttr, &threadSchedParam))!=0)
	{
		cout << "ERROR : Cannot change the thread priority and/or set the scheduler parameters for the thread creation with error "<< returnVal << " - " << strerror(returnVal) << endl;
		return returnVal;
	}
	//if everything has performed properly, return 0
	return returnVal;
}



int DecoderClient::launchThread()
{
	//Create and initialize a control variable
	int returnVal=0;

	//Launch the thread routine
	if((returnVal = pthread_create(&threadID, &threadAttr, decoderClientCoreFunc, &tas))!=0)
	{
	    cout << "ERROR : Cannot launch the new thread with error" << returnVal << " - " << strerror(returnVal) << endl << "Exiting the program ..." << endl;
	    exit(1);
	}

	//if everything has performed properly, return 0
	return returnVal;
}


int DecoderClient::joinThread()
{
	//Create and initialize a control variable
	int returnVal=0;

	//Join the thread in order to be sure that it will be completed before the program stops running
	if((returnVal = pthread_join(threadID, NULL))!=0)
	{
		cout << "ERROR : Cannot wait for the thread to finish with error" << returnVal <<" - " << strerror(returnVal) << endl << "Exiting the program ..." << endl;
		exit(1);
	}

	//if everything has performed properly, return 0
	return returnVal;
}


void* decoderClientCoreFunc(void* ptr)
{
	ThreadArgStruct2* tas = (ThreadArgStruct2*) ptr;
	tas->decoder->decoderClientThreadCoreFuncInClass();

	return NULL;
}


void DecoderClient::decoderClientThreadCoreFuncInClass()
{
#ifdef USE_DECODERS
	GlobalData gbl = GBL_DATA_INIT;
	int quit = FALSE;

	struct ffplayer_config config;
	int status = EXIT_SUCESS;
	AVFormatContext* pFormatCtx;
	int i;
	GAsyncQueue* audioqueue;
	AVPacket* packet;
	pthread_t* audio_thread;
	//pthread_t* video_thread;
	int audioStream=0;
	//int videoStream=0;
	//int nbVideoPacket=0;
	int nbAudioPacket=0;
	AVInputFormat fmt = mp3_demuxer;

	av_register_all();

	if(av_open_input_file(&pFormatCtx,"",fmt,0,NULL)!=0)
			return EX_DATAERR;
	if(av_find_stream_info(pFormatCtx) < 0)
		return EX_DATAERR;

	dump_format(pFormatCtx, 0, "", 0);

	GT_enable();

	pthread_mutex_init(&gbl.mutex, NULL);
	g_thread_init(NULL);

	/*
	 * !! SIGNAUX !!
	 */

	/*
	 * Initialisation du decoder matériel H264
	 */

	/*
	 * Analyse du fichier
	 */

	audioStream = 0; 	//stream_index initialized to 0 in MRSink    for Audio
	//videoStream = 1;	//stream_index initialized to 1 in MR264Sink for Video

	audioqueue = NULL;
	//config.queue = NULL;

	/*
	 * !! INIT DE LA QUEUE VIDEO
	 */

	/*
	 * !! TRAITEMENT DE LA QUEUE VIDEO SI VIDEOSTREAM !=-1
	 */

	audioqueue = g_async_queue_new();
	audio_thread = audio_create(audioqueue, pFormatCtx->streams[audioStream]->codec);

	packet = malloc(sizeof(AVPacket));
	assert(packet != NULL);

	while((sink->getQueueSize())!=0)
	{
		packet = sink->getNext();
		if(packet->stream_index == audioStream && packet->size > 0)
		{
			while((g_async_queue_lenght(audioqueue)) > 3)
			{
				usleep(10000);
			}
			av_dup_packet(packet);
			av_async_queue_push(audioqueue, packet);
			nbAudioPacket++;
		}
		/*else if(packet->stream_index == videoStream && packet->size > 0)
		{
			while((g_async_queue_lenght(config.queue)) >3)
			{
				usleep(10000);
			}
			av_dup_packet(packet);
			av_async_queue_push(confiq.queue, packet);
			nbVideoPacket++;
		}*/
		else
		{
			av_free_packet(packet);
			free(packet);
		}
		packet = malloc(sizeof(AVPacket));
		assert(packet != NULL);
	}

	/*if(nbVideoPacket != 0)
	{
		g_async_queue_lock(config.queue);

		while((packet = g_async_queue_try_pop_unlocked(config.queue)) != NULL)
		{
			av_free_packet(packet);
			free(packet);
		}

		g_async_queue_push_unlocked(config.queue, (void*)0xdeaddead);
		g_async_queue_unlock(config.queue);

		pthread_join(*video_thread, NULL);
	}*/

	if(nbAudioPacket != 0)
	{
		g_async_queue_lock(audioqueue);

		while((packet = g_async_queue_try_pop_unlocked(audioqueue)) != NULL)
		{
			av_free_packet(packet);
			free(packet);
		}

		g_async_queue_push_unlocked(audioqueue, (void*)0xdeaddead);
		g_async_queue_unlock(audioqueue);

		pthread_join(*audio_thread, NULL);
	}

	if(audioqueue != NULL)
	{
		g_async_queue_unref(audioqueue);
	}
	/*if(config.queue != NULL)
	{
		g_async_queue_unref(config.queue);
	}*/

	/*
	 * av_close_input_file(pFormatCtx);
	 */
	pthread_mutex_destroy(&gbl.mutex);
#endif
}


